package com.thunder.kocho.transition

import android.animation.*
import android.content.Context
import android.graphics.Canvas
import android.graphics.Color
import android.graphics.Paint
import android.graphics.Path
import android.graphics.drawable.GradientDrawable
import android.util.AttributeSet
import android.view.View
import android.view.animation.AccelerateInterpolator
import android.view.animation.LinearInterpolator
import com.thunder.kocho.R
import java.util.*

/**
 * 带两种不同执行结果的动画的Button
 * @author Hilex
 * @date 2021-3-13
 */
class ShrinkButton: androidx.appcompat.widget.AppCompatButton,View.OnClickListener {

    private var color:Int
    private var content:String

    private val defaultHeight:Int=200
    private val defaultWidth:Int=500

    private var mWidth:Int=defaultWidth
    private var mHeight:Int=defaultHeight

    private lateinit var gradientDrawable: GradientDrawable
    private lateinit var circlePaint:Paint
    private lateinit var judgePaint:Paint
    private lateinit var correctPath:Path
    private lateinit var wrongPath:Path

    private lateinit var circleAnimator:ValueAnimator//转圈圈
    private lateinit var shrinkAnimator:ValueAnimator//按钮缩小成圆形
    private lateinit var correctAnimatorSet:AnimatorSet//显示正确
    private lateinit var wrongAnimatorSet:AnimatorSet//显示错误
    private lateinit var regainAnimatorSet:AnimatorSet//回退成初始形状
    private lateinit var enhanceAnimatorSet:AnimatorSet//跳转动画
    private var startAngle:Float=0f
    private var canvasScale:Float=1f

    private var centerX:Float=0f
    private var centerY:Float=0f

    private val stillState:Int=0//静止
    private val shrinkState:Int=1//缩小至圆圈，并转圈
    private val circleState:Int=2//已缩小至圆圈，并转圈
    private val wrongState:Int=3//显示错误
    private val correctState=4//显示正确
    private val regainState=5//恢复形状
    private val enhanceState:Int=6//开启转场动画
    private var state:Int=stillState

    interface OnPostListener{
        fun onPostClick()
        fun onNewIntent()
        fun onRegain()
    }

    private lateinit var postListener:OnPostListener

    constructor(context: Context):this(context, null)

    constructor(context: Context, attrs: AttributeSet?):this(context, attrs, 0)

    constructor(context: Context, attrs: AttributeSet?, defStyle: Int):super(context, attrs, defStyle){
        val typedArray=context.obtainStyledAttributes(attrs, R.styleable.ShrinkButton, defStyle, 0)
        color=typedArray.getColor(R.styleable.ShrinkButton_shrinkColor, Color.BLUE)
        content= typedArray.getString(R.styleable.ShrinkButton_shrinkText).toString()
        typedArray.recycle()
        init()
    }

    private fun init(){
        gradientDrawable= GradientDrawable()
        gradientDrawable.setColor(color)
        gradientDrawable.setBounds(0, 0, mWidth, mHeight)

        text = content

        circlePaint=Paint()
        circlePaint.isAntiAlias=true
        circlePaint.color=Color.WHITE
        circlePaint.style=Paint.Style.STROKE
        circlePaint.strokeWidth=7f

        judgePaint= Paint()
        judgePaint.isAntiAlias=true
        judgePaint.color=Color.WHITE
        judgePaint.style=Paint.Style.STROKE
        judgePaint.strokeWidth=8f

        circleAnimator=ValueAnimator.ofFloat(0f, 360f)
        circleAnimator.addUpdateListener{ animator->
            startAngle=animator.animatedValue as Float
            invalidate()
        }
        circleAnimator.duration=600
        circleAnimator.interpolator=LinearInterpolator()
        circleAnimator.repeatCount=-1

        val scaleAnimator= ValueAnimator.ofFloat(0f, 1f)
        scaleAnimator.addUpdateListener{ animator->
            canvasScale=animator.animatedValue as Float
            invalidate()
        }
        scaleAnimator.duration=600
        scaleAnimator.interpolator=AccelerateInterpolator()
        val greenHolder=PropertyValuesHolder.ofInt("DrawableColor", color, Color.parseColor("#FF10B817"))
        val greenAnimator=ObjectAnimator.ofPropertyValuesHolder(this, greenHolder)
        greenAnimator.setEvaluator(ArgbEvaluator())
        greenAnimator.duration=500
        greenAnimator.interpolator=LinearInterpolator()
        correctAnimatorSet= AnimatorSet()
        correctAnimatorSet.playTogether(scaleAnimator, greenAnimator)

        val redHolder=PropertyValuesHolder.ofInt("DrawableColor", color, Color.parseColor("#FFF31B1B"))
        val redAnimator=ObjectAnimator.ofPropertyValuesHolder(this, redHolder)
        redAnimator.setEvaluator(ArgbEvaluator())
        redAnimator.duration=500
        redAnimator.interpolator=LinearInterpolator()
        wrongAnimatorSet= AnimatorSet()
        wrongAnimatorSet.playTogether(scaleAnimator,redAnimator)

        regainAnimatorSet= AnimatorSet()
        enhanceAnimatorSet= AnimatorSet()

        setOnClickListener(this)
    }

    override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec)
        val widthMode = MeasureSpec.getMode(widthMeasureSpec)
        val widthSize = MeasureSpec.getSize(widthMeasureSpec)
        val heightMode = MeasureSpec.getMode(heightMeasureSpec)
        val heightSize = MeasureSpec.getSize(heightMeasureSpec)
        if (widthMode == MeasureSpec.EXACTLY) {
            mWidth = widthSize
        }
        if (heightMode == MeasureSpec.EXACTLY) {
            mHeight = heightSize
        }

        centerX=mWidth/2f
        centerY=mHeight/2f

        gradientDrawable.cornerRadius=mHeight/2f
        background=gradientDrawable

        initAnimator()
        initPath()
    }

    override fun onDraw(canvas: Canvas?) {
        super.onDraw(canvas)
        when(state){
            shrinkState -> canvas?.drawArc(mWidth / 2f - mHeight / 4f, mHeight / 4f, mWidth / 2f + mHeight / 4f, 3 * mHeight / 4f, startAngle, 240f, false, circlePaint)

            circleState -> canvas?.drawArc(mWidth / 2f - mHeight / 4f, mHeight / 4f, mWidth / 2f + mHeight / 4f, 3 * mHeight / 4f, startAngle, 240f, false, circlePaint)

            correctState -> {
                canvas?.save()
                canvas?.scale(canvasScale, canvasScale, centerX, centerY)
                canvas?.drawPath(correctPath, judgePaint)
                canvas?.restore()
            }

            wrongState -> {
                canvas?.save()
                canvas?.scale(canvasScale, canvasScale, centerX, centerY)
                canvas?.drawPath(wrongPath, judgePaint)
                canvas?.restore()
            }

            enhanceState->{
                canvas?.save()
                canvas?.scale(canvasScale, canvasScale, centerX, centerY)
                canvas?.drawPath(correctPath, judgePaint)
                canvas?.restore()
            }

        }
    }

    override fun onClick(v: View?) {
        if(state!=stillState){
            return
        }
        onShrink()
        if(this::postListener.isInitialized){
            postListener.onPostClick()
        }
    }

    private fun initAnimator(){
        shrinkAnimator= ValueAnimator.ofInt(0, mWidth / 2 - mHeight / 2)
        shrinkAnimator.removeAllListeners()
        shrinkAnimator.addUpdateListener { animation ->
            val leftOffset = animation.animatedValue as Int
            val rightOffset = mWidth - leftOffset
            gradientDrawable.setBounds(leftOffset, 0, rightOffset, mHeight)
            background=gradientDrawable
        }
        shrinkAnimator.duration = 1000
        shrinkAnimator.addListener(object : Animator.AnimatorListener {

            override fun onAnimationStart(animation: Animator?) {
                state = shrinkState

            }

            override fun onAnimationEnd(animation: Animator?) {
                if(state!=stillState){
                    state = circleState
                }
            }

            override fun onAnimationCancel(animation: Animator?) {

            }

            override fun onAnimationRepeat(animation: Animator?) {

            }
        })

        val regainColorHolder=PropertyValuesHolder.ofInt("DrawableColor", Color.parseColor("#FFF31B1B"), color)
        regainColorHolder.setEvaluator(ArgbEvaluator())
        val regainColorAnimator=ObjectAnimator.ofPropertyValuesHolder(this, regainColorHolder)
        val regainOffsetAnimator= ValueAnimator.ofInt(mWidth / 2 - mHeight / 2, 0)
        regainOffsetAnimator.removeAllListeners()
        regainOffsetAnimator.addUpdateListener { animation ->
            val leftOffset = animation.animatedValue as Int
            val rightOffset = mWidth - leftOffset
            gradientDrawable.setBounds(leftOffset, 0, rightOffset, mHeight)
            background=gradientDrawable
        }
        regainAnimatorSet.playTogether(regainColorAnimator, regainOffsetAnimator)
        regainAnimatorSet.duration=1000
        regainAnimatorSet.removeAllListeners()
        regainAnimatorSet.addListener(object : Animator.AnimatorListener {
            override fun onAnimationStart(animation: Animator?) {

            }

            override fun onAnimationEnd(animation: Animator?) {
                if(state!=stillState){
                    text = context.getString(R.string.login)
                    state = stillState
                }
            }

            override fun onAnimationCancel(animation: Animator?) {

            }

            override fun onAnimationRepeat(animation: Animator?) {

            }
        })
        wrongAnimatorSet.removeAllListeners()
        wrongAnimatorSet.addListener(object : Animator.AnimatorListener {
            override fun onAnimationStart(animation: Animator?) {

            }

            override fun onAnimationEnd(animation: Animator?) {
                if(state==stillState){
                    return
                }
                if (this@ShrinkButton::postListener.isInitialized) {
                    postListener.onRegain()
                }
                val timer = Timer()
                val task = object : TimerTask() {
                    override fun run() {
                        state = regainState
                        post {
                            regainAnimatorSet.start()
                        }
                    }
                }
                timer.schedule(task, 600)
            }

            override fun onAnimationCancel(animation: Animator?) {

            }

            override fun onAnimationRepeat(animation: Animator?) {

            }
        })

        val correctFadeAnimator= ValueAnimator.ofFloat(1f,0f)
        correctFadeAnimator.removeAllListeners()
        correctFadeAnimator.addUpdateListener{ animator->
            val value=animator.animatedValue as Float
            canvasScale=value/scaleY
            invalidate()
        }
        correctFadeAnimator.interpolator=AccelerateInterpolator()
        correctFadeAnimator.duration=600
        val enhanceAnimator=ValueAnimator.ofFloat(1f,24f)
        enhanceAnimator.removeAllListeners()
        enhanceAnimator.addUpdateListener{animator->
            scaleX=animator.animatedValue as Float
            scaleY=animator.animatedValue as Float
        }
        enhanceAnimator.interpolator=AccelerateInterpolator()
        enhanceAnimator.duration=800
        val backgroundFadeAnimator=ValueAnimator.ofFloat(1f,0.15f)
        backgroundFadeAnimator.removeAllListeners()
        backgroundFadeAnimator.addUpdateListener{ animator->
            val parentView=parent as View
            parentView.alpha=animator.animatedValue as Float
        }
        backgroundFadeAnimator.duration=800
        backgroundFadeAnimator.interpolator=AccelerateInterpolator()
        enhanceAnimatorSet.playTogether(correctFadeAnimator,enhanceAnimator,backgroundFadeAnimator)
        enhanceAnimatorSet.removeAllListeners()
        enhanceAnimatorSet.addListener(object :Animator.AnimatorListener{
            override fun onAnimationStart(animation: Animator?) {

            }

            override fun onAnimationEnd(animation: Animator?) {
                if(state==stillState){
                    return
                }
                if(this@ShrinkButton::postListener.isInitialized){
                    postListener.onNewIntent()
                }
            }

            override fun onAnimationCancel(animation: Animator?) {

            }

            override fun onAnimationRepeat(animation: Animator?) {

            }
        })
        correctAnimatorSet.removeAllListeners()
        correctAnimatorSet.addListener(object :Animator.AnimatorListener{
            override fun onAnimationStart(animation: Animator?) {

            }

            override fun onAnimationEnd(animation: Animator?) {
                if(state==stillState){
                    return
                }
                val timer = Timer()
                val task = object : TimerTask() {
                    override fun run() {
                        post {
                            state=enhanceState
                            enhanceAnimatorSet.start()
                        }
                    }
                }
                timer.schedule(task, 600)
            }

            override fun onAnimationCancel(animation: Animator?) {

            }

            override fun onAnimationRepeat(animation: Animator?) {

            }
        })
    }

    private fun initPath(){
        val ox=mWidth/2f-mHeight/4f
        val oy=mHeight/4f
        correctPath= Path()
        correctPath.moveTo(ox + mHeight / 16f, oy + 3 * mHeight / 10f)
        correctPath.lineTo(ox + 3 * mHeight / 16f, oy + 2 * mHeight / 5f)
        correctPath.lineTo(ox + 7 * mHeight / 16f, oy + mHeight / 10f)
        wrongPath= Path()
        wrongPath.moveTo(ox + mHeight * 3 / 32f, oy + mHeight * 3 / 32f)
        wrongPath.lineTo(ox + mHeight * 13 / 32f, oy + mHeight * 13 / 32f)
        wrongPath.moveTo(ox + mHeight * 13 / 32f, oy + mHeight * 3 / 32f)
        wrongPath.lineTo(ox + mHeight * 3 / 32f, oy + mHeight * 13 / 32f)
    }

    private fun setDrawableColor(color: Int){
        gradientDrawable.setColor(color)
        background=gradientDrawable
    }

    private fun onShrink(){
        if(state!=stillState||!this::shrinkAnimator.isInitialized||!this::circleAnimator.isInitialized){
            return
        }
        text=""
        shrinkAnimator.start()
        circleAnimator.start()
    }

    fun onCorrect(){
        if(state==circleState){
            circleAnimator.end()
            state=correctState
            correctAnimatorSet.start()
        }else if(state==shrinkState){
            shrinkAnimator.addListener(object:Animator.AnimatorListener{
                override fun onAnimationStart(animation: Animator?) {

                }

                override fun onAnimationEnd(animation: Animator?) {
                    if(state!=stillState){
                        circleAnimator.end()
                        state=correctState
                        correctAnimatorSet.start()
                    }
                }

                override fun onAnimationCancel(animation: Animator?) {

                }

                override fun onAnimationRepeat(animation: Animator?) {

                }
            })
        }
    }

    fun onWrong(){
        if(state==circleState){
            circleAnimator.end()
            state=wrongState
            wrongAnimatorSet.start()
        }else if(state==shrinkState){
            shrinkAnimator.addListener(object:Animator.AnimatorListener{
                override fun onAnimationStart(animation: Animator?) {

                }

                override fun onAnimationEnd(animation: Animator?) {
                    if(state!=stillState){
                        circleAnimator.end()
                        state=wrongState
                        wrongAnimatorSet.start()
                    }
                }

                override fun onAnimationCancel(animation: Animator?) {

                }

                override fun onAnimationRepeat(animation: Animator?) {

                }
            })
        }
    }

    fun setOnPostListener(postListener: OnPostListener){
        this.postListener=postListener
    }

    override fun onVisibilityChanged(changedView: View, visibility: Int) {
        super.onVisibilityChanged(changedView, visibility)
        when(visibility){
            INVISIBLE, GONE->{
                if(state==stillState){
                    return
                }
                state=stillState
                clearAnimation()
                scaleY=1f
                scaleX=1f
                gradientDrawable.setColor(color)
                gradientDrawable.setBounds(0, 0, mWidth, mHeight)
                gradientDrawable.cornerRadius=mHeight/2f
                background=gradientDrawable
                text=content
                val parentView=parent as View
                parentView.alpha=1f
                canvasScale=1f
            }
            VISIBLE->{

            }
        }
    }
}